<?php

/*
 * Copyright 2008 the original author or authors.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#namespace tehframework\annotations\builders;

#use tehframework\annotations\TagDefinition;
#use tehframework\annotations\tags\UnknownTag;
#use tehframework\testing\phpunit\TestCase;

require_once 'test/testHelper.php';

class TagBuilderImplTest extends TestCase
{
	const UNKNOWN_TAG_CLASS = 'UnknownTag';
	const UNKNOWN_TAG = 'hopefullyUnknownTag';
	
	function testMapTagToClassThrowsExceptionIfTagNameIsNotNonEmptyString()
	{
		$this->setExpectedException('InvalidArgumentException');
		
		$builder = new TagBuilderImpl();
		$builder->mapTagToClass('', self::UNKNOWN_TAG_CLASS);
	}
	
	function testMapTagToClassThrowsExceptionIfClassCouldNotBeFound()
	{
		$this->setExpectedException('InvalidArgumentException');
		
		$builder = new TagBuilderImpl();
		$builder->mapTagToClass(self::UNKNOWN_TAG, 'HopyfullyIDoNotExist');
	}
	
	function testMapTagsToClassesThrowsExceptionIfAnyTagNameIsNotNonEmptyString()
	{
		$this->setExpectedException('InvalidArgumentException');
		
		$builder = new TagBuilderImpl();
		$builder->mapTagsToClasses(array(
			self::UNKNOWN_TAG => self::UNKNOWN_TAG_CLASS, self::UNKNOWN_TAG_CLASS));
	}
	
	function testMapTagsToClassesThrowsExceptionIfAnyClassCouldNotBeFound()
	{
		$this->setExpectedException('InvalidArgumentException');
		
		$builder = new TagBuilderImpl();
		$builder->mapTagsToClasses(array(
			self::UNKNOWN_TAG => self::UNKNOWN_TAG_CLASS,
			'param' => 'HopyfullyIDoNotExist'));
	}
	
	function testSetClassForUnknownTagsThrowsExceptionIfClassCouldNotBeFound()
	{
		$this->setExpectedException('InvalidArgumentException');
		
		$builder = new TagBuilderImpl();
		$builder->setClassForUnknownTags('HopefullyIDoNotExist');
	}
	
	function testBuildTagUsesClassesMappedToTagNames()
	{
		$this->requireClass('tehframework\\annotations\\tags\\UnknownTag');
		
		$builder = new TagBuilderImpl();
		
		$tag = $builder
			->mapTagToClass(self::UNKNOWN_TAG, self::UNKNOWN_TAG_CLASS)
			->buildTag(new TagDefinition(self::UNKNOWN_TAG));
		
		$this->assertType(self::UNKNOWN_TAG_CLASS, $tag);
		$this->assertSame(self::UNKNOWN_TAG, $tag->getName());
	}
	
	function testBuildTagUsesSpecifiedClassForUnknownTags()
	{
		$this->requireClass('tehframework\\annotations\\tags\\UnknownTag');
		
		$builder = new TagBuilderImpl();
		
		$tag = $builder
			->setClassForUnknownTags(self::UNKNOWN_TAG_CLASS)
			->buildTag(new TagDefinition(self::UNKNOWN_TAG));
		
		$this->assertType(self::UNKNOWN_TAG_CLASS, $tag);
		$this->assertSame(self::UNKNOWN_TAG, $tag->getName());
	}
	
	function testBuildTagThrowsExceptionIfTagClassCanNotBeResolved()
	{
		$this->setExpectedException('BuilderException');
		
		$builder = new TagBuilderImpl();
		$builder->buildTag(new TagDefinition('hopefullyIDoNotExist'));
	}
	
	function testBuildTagResolvesClassesBasedOnPredefinedFormatWithoutAutoload()
	{
		$this->requireClass('tehframework\\annotations\\tags\\UnknownTag');
		
		$builder = new TagBuilderImpl();
		
		$tag = $builder->disableAutoload()->buildTag(new TagDefinition('unknown'));
		
		$this->assertType('UnknownTag', $tag);
		$this->assertSame('unknown', $tag->getName());
	}
	
	function testBuildTagResolvesClassesBasedOnPredefinedFormatWithAutoload()
	{
		$builder = new TagBuilderImpl();
		
		$tag = $builder->enableAutoload()->buildTag(new TagDefinition('unknown'));
		
		$this->assertType('UnknownTag', $tag);
		$this->assertSame('unknown', $tag->getName());
	}
	
	function testBuildTagUsesSpecifiedNamespacesToResolveTagClass()
	{
		if (version_compare(PHP_VERSION, '5.3', '<'))
		{
			$this->markTestSkipped('No namespaces in PHP <5.3.');
		}
		
		$builder = new TagBuilderImpl();
		
		$tag = $builder
			->addNamespaces(array('tehframework\\annotations\\tags'))
			->enableAutoload()
			->buildTag(new TagDefinition('unknown'));
		
		$this->assertType('tehframework\\annotations\\tags\\UnknownTag', $tag);
		$this->assertSame('unknown', $tag->getName());
	}
	
	function testBuildTagThrowsExceptionIfFoundTagClassDoesNotImplementTagInterface()
	{
		$this->setExpectedException('BuilderException');
		
		$builder = new TagBuilderImpl();
		$builder
			->mapTagToClass(self::UNKNOWN_TAG, 'stdClass')
			->buildTag(new TagDefinition(self::UNKNOWN_TAG));
	}
}